package com.jch.dm2_guarded_suspension.demo_code;

import com.jch.dm2_guarded_suspension.reusable_code.Blocker;
import com.jch.dm2_guarded_suspension.reusable_code.ConditionVarBlocker;
import com.jch.dm2_guarded_suspension.reusable_code.GuardedAction;
import com.jch.dm2_guarded_suspension.reusable_code.Predicate;

import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Callable;

// 非嵌套监视器
public class MonitorLockoutExample {

    public static void main(String[] args) {
        final Helper helper = new Helper();
        System.out.println("Before calling guardedMethod.");
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                String result;
                result = helper.guardedMethod("text");
                System.out.println(result);
            }
        });
        t.start();
        final Timer timer = new Timer();
        // 延迟50ms调用helper.stateChanged方法
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                helper.stateChanged();
                timer.cancel();
            }
        }, 50, 10);

    }

    private static class Helper {

        private volatile boolean isStateOK = false;

        private final Predicate stateBeOK = new Predicate() {
            @Override
            public boolean evaluate() {
                return isStateOK;
            }
        };

        private final Blocker blocker = new ConditionVarBlocker();

        public String guardedMethod(final String msg) {
            GuardedAction<String> guardedAction = new GuardedAction<String>(stateBeOK) {
                @Override
                public String call() throws Exception {
                    return msg + "->received.";
                }
            };
            String result = null;
            try {
                result = blocker.callWithGuard(guardedAction);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return result;
        }

        public void stateChanged() {
            try {
                blocker.signalAfter(new Callable<Boolean>() {
                    @Override
                    public Boolean call() throws Exception {
                        isStateOK = true;
                        System.out.println("state ok.");
                        return Boolean.TRUE;
                    }
                });
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}
